/**
 * Class: PComponent
 *
 * Purpose: 
 *
 * Created: Jan 21, 2010 @ 10:21:48 AM
 * @author Ken Scott
 */
package org.openfantasia.ui;

import processing.core.PApplet;

import java.util.HashMap;
import java.util.Map;

public class PComponent implements IComponent {

	public static final String BORDER = "border";

	public static final String FILL = "fill";

	private PApplet applet;

	private PComponent container;

	private PLayer background = new PLayer(this);

	private PLayer controls = new PLayer(this);

	private PLayer foreground = new PLayer(this);

	private Map<String, PColor> colorMap = new HashMap<String, PColor>();

	private float x = 0;

	private float y = 0;

	private float width = 0;

	private float height = 0;

	private boolean clickThrough = false;


	public PComponent() {
		prep(0, 0, 0, 0, false);
	}


	public PComponent(float x, float y, float width, float height) {
		prep(x, y, width, height, false);
	}


	public PComponent(float x, float y, float width, float height, boolean clickThrough) {
		prep(x, y, width, height, clickThrough);
	}


	protected void prep(float x, float y, float width, float height, boolean clickThrough) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		this.clickThrough = clickThrough;
	}


	public void setBounds(float x, float y, float w, float h) {
		this.x = x;
		this.y = y;
		this.width = w;
		this.height = h;
	}


	public void setup() {
		background.setup();
		controls.setup();
		foreground.setup();
	}


	public void draw() {
		drawPrep();
		drawBackground();
		drawDynamic();
		drawControls();
		drawForeground();
	}


	public void drawPrep() {
	}


	public void drawDynamic() {
	}


	public void drawControls() {
		controls.draw();
	}


	public void drawForeground() {
		foreground.draw();
	}


	public void drawBackground() {
		background.draw();
	}


	public float globalMouseX() {
		return getApplet().mouseX;
	}


	public float globalMouseY() {
		return getApplet().mouseY;
	}


	public float mouseX() {
		return globalMouseX() - getGlobalX();
	}


	public float mouseY() {
		return globalMouseY() - getGlobalY();
	}


	public void setColor(String name, PColor value) {
		colorMap.put(name, value);
	}


	public PColor getColor(String name) {
		return colorMap.get(name);
	}


	public PComponent getContainer() {
		return container;
	}


	public void setContainer(PComponent container) {
		this.container = container;
	}


	public PApplet getApplet() {
		if (applet != null) {
			return applet;
		}
		else {
			return container.getApplet();
		}
	}


	public void setApplet(PApplet applet) {
		this.applet = applet;
	}


	public void addBackground(PComponent child) {
		background.add(child);
	}


	public void removeBackground(PComponent child) {
		background.remove(child);
	}


	public void addForeground(PComponent child) {
		foreground.add(child);
	}


	public void removeForeground(PComponent child) {
		foreground.remove(child);
	}


	public void addControl(PComponent child) {
		controls.add(child);
	}


	public void removeControl(PComponent child) {
		controls.remove(child);
	}


	public float getX() {
		return x;
	}


	public void setX(float x) {
		this.x = x;
	}


	public float getY() {
		return y;
	}


	public void setY(float y) {
		this.y = y;
	}


	public float getGlobalX() {
		PComponent c = getContainer();
		return (c != null ? c.getGlobalX() : 0) + x;
	}


	public float getGlobalY() {
		PComponent c = getContainer();
		return (c != null ? c.getGlobalY() : 0) + y;
	}


	public float getWidth() {
		return width;
	}


	public void setWidth(float width) {
		this.width = width;
	}


	public float getHeight() {
		return height;
	}


	public void setHeight(float height) {
		this.height = height;
	}


	public boolean isClickThrough() {
		return clickThrough;
	}


	public void setClickThrough(boolean clickThrough) {
		this.clickThrough = clickThrough;
	}

	// Sensing

	private boolean tracking = false;

	private boolean highlight = false;


	public void mousePressed() {
		for (PComponent control : controls) {
			control.mousePressed();
		}
		tracking = getComponentUnderMouse() == this;
	}


	public void mouseReleased() {
		for (PComponent control : controls) {
			control.mouseReleased();
		}

		if (tracking) {
			tracking = false;
			if (getComponentUnderMouse() == this) {
				mouseClicked();
			}
		}
	}


	public boolean isTracking() {
		return tracking;
	}


	public void mouseClicked() {
	}


	public void mouseDragged() {
	}


	public void mouseMoved() {
		highlight = getComponentUnderMouse() == this;
	}


	public boolean isOver() {
		return isPointInRect(globalMouseX(), globalMouseY(), getGlobalX(), getGlobalY(), getWidth(), getHeight());
	}


	public boolean isPressed() {
		return isOver() && getApplet().mousePressed;
	}


	public static boolean isPointInRect(float px, float py, float rx, float ry, float rw, float rh) {
		return (px >= rx) && (px < rx + rw) && (py >= ry) && (py < ry + rh);
	}


	public PComponent getComponentUnderMouse() {
		PComponent result = null;

		if (isOver()) {
			for (int i = 0; i < controls.size(); i++) {
				PComponent sub = controls.get(i).getComponentUnderMouse();
				if (sub != null) {
					result = sub;
				}
			}
			if (result == null) {
				result = this;
			}
		}

		return result;
	}

	// Drawing methods


	public void noFill() {
		getApplet().noFill();
	}


	public void noStroke() {
		getApplet().noStroke();
	}


	public void fill(float r, float g, float b, float a) {
		getApplet().fill(r, g, b, a);
	}


	public void fill(PColor c) {
		getApplet().fill(c.p[0], c.p[1], c.p[2], c.p[3]);
	}


	public void stroke(float r, float g, float b, float a) {
		getApplet().stroke(r, g, b, a);
	}


	public void stroke(PColor c) {
		getApplet().stroke(c.p[0], c.p[1], c.p[2], c.p[3]);
	}


	public void rectMode(int mode) {
		getApplet().rectMode(mode);
	}


	public void rect(float x, float y, float w, float h) {
		getApplet().rect(getGlobalX() + x, getGlobalY() + y, w, h);
	}


	public void ellipseMode(int mode) {
		getApplet().ellipseMode(mode);
	}


	public void ellipse(float x, float y, float w, float h) {
		getApplet().ellipse(getGlobalX() + x, getGlobalY() + y, w, h);
	}


	public void line(float x1, float y1, float x2, float y2) {
		float gx = getGlobalX();
		float gy = getGlobalY();
		getApplet().line(gx + x1, gy + y1, gx + x2, gy + y2);
	}

	public void text(String str, float x, float y) {
		float gx = getGlobalX() + x;
		float gy = getGlobalY() + y;
		getApplet().text(str, gx, gy);
	}
}
